import os,datetime,time,glob,hashlib,sys,importlib
from .model import peaktask,peaktasklog
from .setting import *
from playhouse.shortcuts import model_to_dict
from datetime import timedelta

def init():
    taskmodel = peaktask()
    taskmodel.init()

    tasklogmodel = peaktasklog()
    tasklogmodel.init()

def reloadtasks(sched):
    taskmodel = peaktask()

    # 扫描任务目录，更新数据库
    _scantaskdir(taskmodel,sched)

    # 扫描数据库，提取出正常的任务列表
    taskids,tasks = _scandb(taskmodel,sched)

    # 扫描队列列表，如果有job不在队列中，则删除
    for job in getrunningjobs(sched):
        if not job.id in taskids:
            pass
            sched.remove_job( job.id )

    return tasks

def _scandb(taskmodel,sched):
    taskmodel = peaktask()
    # 扫描数据库，发现有记录未加载，则添加
    taskids = []
    tasks = []
    for task in taskmodel.select():
        jobid = 'task_{}'.format(task.id)
        name = task.name
        taskmodulename = 'peaktask.tasks.{}'.format(name)
        filepath = "peaktask/tasks/{}.py".format(name)
        # 如果该任务文件被删除，则删除数据库记录和任务记录
        if os.path.isfile(filepath) == False:
            taskmodel.delete_by_id(task.id)
            if sched.get_job( jobid ):
                del sys.modules[taskmodulename]
                sched.remove_job( jobid )
            continue
        # 如果任务文件未执行，则添加至任务列表中
        if not sched.get_job( jobid ):
            addjob(task,sched)
        # 将任务文件添加至列表中，等待下步进行比对
        taskids.append(jobid)
        tasks.append(task)
    return taskids,tasks

def _scantaskdir(taskmodel,sched):
    taskmodel = peaktask()
    # 扫描脚本目录，发现有文件被修改或者是新文件，则添加至数据库，等待后面步骤进行处理
    for task in glob.glob(r'peaktask/tasks/*.py'):
        taskname = os.path.basename(task)[0:-3]
        if taskname == '__init__':
            continue
        with open(task,encoding='utf-8') as f:
            content = f.read()
            m = hashlib.md5()
            b = content.encode(encoding='utf-8')
            m.update(b)
            sign = m.hexdigest()
            taskmodulename = 'peaktask.tasks.{}'.format(taskname)
            taskmodule = None
            taskconfig = None
            try:
                taskmodule = importlib.import_module(taskmodulename, ".")
                importlib.reload(taskmodule)
                taskconfig = getattr(taskmodule, 'config')
            except Exception as ex:
                print(str(ex))

            needdel = False
            if taskconfig == None:
                needdel = True
            elif not taskconfig['name'] or not taskconfig['interval'] or not taskconfig['title']:
                needdel = True
            existmodel = taskmodel.get_or_none( name = taskname )
            # 如果数据库中存在记录，且新脚本读取失败，则删除数据库记录
            if existmodel and needdel:
                print('脚本文件不正确，请核实后重试:{}'.format(taskname))
                jobid = 'task_{}'.format(existmodel.id)
                if sched.get_job(jobid):
                    sched.remove_job(jobid)
                del sys.modules[taskmodulename]
                taskmodel.delete_by_id(existmodel.id)
                continue

            # 如果数据库中存在记录，但是摘要不一致，则视为修改
            if existmodel and existmodel.sign != sign:
                # 更新数据库内容
                existmodel.content = content
                existmodel.sign = sign
                existmodel.status = ''
                existmodel.title = taskconfig['title']
                existmodel.name = taskname
                existmodel.remark = taskconfig['remark'] if taskconfig['remark'] else ''
                existmodel.interval = taskconfig['interval']
                existmodel.nexttime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                existmodel.save()
                # 删除正在运行的任务
                jobid = 'task_{}'.format(existmodel.id)
                if sched.get_job(jobid):
                    sched.remove_job(jobid)
                del sys.modules[taskmodulename]
                continue

            # 如果数据库中不存在记录，则添加至数据库
            if not existmodel:
                if needdel == True:
                    continue
                addmodel = peaktask()
                addmodel.name = taskname
                addmodel.content = content
                addmodel.sign = sign
                addmodel.status = ''
                addmodel.title = taskconfig['title']
                addmodel.remark = taskconfig['remark'] if taskconfig['remark'] else ''
                addmodel.interval = taskconfig['interval']
                addmodel.nexttime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                addmodel.save()

def getrunningjobs(sched):
    tasklist = []
    for job in sched.get_jobs():
        if job.id == SCANKEY:
            continue
        tasklist.append(job)
    return  tasklist

def wraplog(name):
    def wrapper(f):
        def inner(*args, **kwargs):
            status = ''
            log = ''
            try:
                f(*args, **kwargs)
                status = '正常'
            except Exception as ex:
                status = '异常'
                log = str(ex)
            finally:
                task = peaktask.get_or_none(name=name)
                if task:
                    peaktasklog.create(addtime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), status=status, log=log,taskid=task.id)
                    nexttime = task.nexttime
                    interval = datetime.timedelta(minutes=task.interval)
                    nexttime = nexttime+ interval
                    task.nexttime = nexttime
                    task.status = status
                    task.save()
        return inner
    return wrapper

def addjob(task,sched):
    jobid = 'task_{}'.format(task.id)
    if not sched.get_job(jobid):
        taskmodulename = 'peaktask.tasks.{}'.format(task.name)
        taskmodule = importlib.import_module(taskmodulename, ".")
        importlib.reload(taskmodule)
        run = getattr(taskmodule, 'run')
        try:
            sched.add_job(func=run, trigger='interval', minutes=task.interval, id=jobid, name=task.name, next_run_time=datetime.datetime.now())
        except Exception as ex:
            print('脚本 {} 出错:{}'.format(task.name,str(ex)))

if __name__=='__main__':
    pass
